package concurrent;

import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 并行搜索
 * 一种简单的策略就是将原始的数据集合按照期望的线程数进行分割。
 *
 */
public class ConcurrencySearch {

    //待查找的数组
    static int[] arr;

    static ExecutorService pool = Executors.newCachedThreadPool();
    //线程数量
    static final int THREAD_NUM = 2;
    //存放结果的变量
    static AtomicInteger result = new AtomicInteger(-1);


    /**
     * 每个线程搜索arr中的一段，因此，
     * 搜索函数必须指定线程需要搜索的起始位置和结束位置
     * @param searchValue
     * @param beginPos
     * @param endPos
     * @return
     */
    public static int search(int searchValue, int beginPos, int endPos) {
        System.out.println("searchValue = " + searchValue);
        System.out.println("beginPos = " + beginPos);
        System.out.println("endPos = " + endPos);
        int i=0;
        for (i=beginPos;i<endPos;i++) {
            if (result.get() >=0) {
                return result.get();
            }
            if (arr[i] == searchValue) {
                //如果设置失败， 表示其他线程已经找到了
                if (!result.compareAndSet(-1, 1)) {
                    return result.get();
                }
                return i;
            }
        }
        return -1;
    }

    public static class SearchTask implements Callable<Integer> {
        int searchValue, begin, end;

        public SearchTask(int searchValue, int begin, int end) {
            this.searchValue = searchValue;
            this.begin = begin;
            this.end = end;
        }

        @Override
        public Integer call() throws Exception {
            return search(searchValue, begin, end);
        }
    }

    public static int pSearch(int searchValue) throws ExecutionException, InterruptedException {
        int subArrSize = arr.length/THREAD_NUM+1;
        List<Future<Integer>> re = new ArrayList<>();
        for (int i=0; i<arr.length; i+=subArrSize) {
            int end = i + subArrSize;
            if (end >= arr.length) {
                end = arr.length;
            }
            re.add(pool.submit(new SearchTask(searchValue, i, end)));
        }
        for (Future<Integer> fu : re) {
            if (fu.get()>=0)
                return fu.get();
        }
        return -1;
    }

    @Test
    public void test() throws ExecutionException, InterruptedException {
        arr = new int[]{1, 2, 4, 5, 23, 5, 65, 31, 5, 3, 5};
        pSearch(2);
        Thread.sleep(2000);
        System.out.println(result.get());
    }

}
